home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS05.ADF / asm / mydev.asm < prev    next >
Assembly Source File  |  1986-01-15  |  25KB  |  943 lines

  1.  
  2. * mydev.asm AmigaLink 1/30/86
  3. *************************************************************************
  4. *                                            *
  5. *    Copyright (C) 1985, Commodore Amiga Inc.  All rights reserved.   *
  6. *                                            *
  7. ************************************************************************/
  8.  
  9.  
  10. *************************************************************************
  11. *
  12. * mydev.asm -- skeleton device code
  13. *
  14. * Source Control
  15. * ------ -------
  16. * $Header: amain.asm,v 31.3 85/10/18 19:04:04 neil Exp $
  17. *
  18. * $Locker: neil $
  19. *
  20. * $Log:   amain.asm,v $
  21. *
  22. ************************************************************************/
  23.      SECTION   section
  24.  
  25.      NOLIST
  26.      include "exec/types.i"
  27.      include "exec/nodes.i"
  28.      include "exec/lists.i"
  29.      include "exec/libraries.i"
  30.      include "exec/devices.i"
  31.      include "exec/io.i"
  32.      include "exec/alerts.i"
  33.      include "exec/initializers.i"
  34.      include "exec/memory.i"
  35.      include "exec/resident.i"
  36.      include "exec/ables.i"
  37.      include "exec/errors.i"
  38.      include "libraries/dos.i"
  39.      include "libraries/dosextens.i"
  40.  
  41.      include "asmsupp.i"
  42.      include "messages.i"
  43.  
  44.      include "mydev.i"
  45.  
  46.      LIST
  47.  
  48. INFO_LEVEL equ 40
  49.  
  50.      ;------ These don't have to be external, but it helps some
  51.      ;------ debuggers to have them globally visible
  52.      XDEF Init
  53.      XDEF Open
  54.      XDEF Close
  55.      XDEF Expunge
  56.      XDEF Null
  57.      XDEF myName
  58.      XDEF BeginIO
  59.      XDEF AbortIO
  60.  
  61.      XREF _AbsExecBase
  62.  
  63.      XLIB OpenLibrary
  64.      XLIB CloseLibrary
  65.      XLIB Alert
  66.      XLIB FreeMem
  67.      XLIB Remove
  68.      XLIB FindTask
  69.      XLIB AllocMem
  70.      XLIB CreateProc
  71.      XLIB PutMsg
  72.      XLIB RemTask
  73.      XLIB ReplyMsg
  74.      XLIB Signal
  75.      XLIB GetMsg
  76.      XLIB Wait
  77.      XLIB WaitPort
  78.      XLIB AllocSignal
  79.      XLIB SetTaskPri
  80.  
  81.      INT_ABLES
  82.  
  83.  
  84.      ; The first executable location.  This should return an error
  85.      ; in case someone tried to run you as a program (instead of
  86.      ; loading you as a library).
  87. FirstAddress:
  88.      CLEAR     d0
  89.      rts
  90.  
  91. ;-----------------------------------------------------------------------
  92. ; A romtag structure.  Both "exec" and "ramlib" look for
  93. ; this structure to discover magic constants about you
  94. ; (such as where to start running you from...).
  95. ;-----------------------------------------------------------------------
  96.  
  97.      ; Most people will not need a priority and should leave it at zero.
  98.      ; the RT_PRI field is used for configuring the roms.  Use "mods" from
  99.      ; wack to look at the other romtags in the system
  100. MYPRI     EQU  0
  101.  
  102. initDDescrip:
  103.                          ;STRUCTURE RT,0
  104.        DC.W    RTC_MATCHWORD       ; UWORD RT_MATCHWORD
  105.        DC.L    initDDescrip        ; APTR  RT_MATCHTAG
  106.        DC.L    EndCode        ; APTR  RT_ENDSKIP
  107.        DC.B    RTF_AUTOINIT        ; UBYTE RT_FLAGS
  108.        DC.B    VERSION        ; UBYTE RT_VERSION
  109.        DC.B    NT_DEVICE      ; UBYTE RT_TYPE
  110.        DC.B    MYPRI               ; BYTE  RT_PRI
  111.        DC.L    myName         ; APTR  RT_NAME
  112.        DC.L    idString       ; APTR  RT_IDSTRING
  113.        DC.L    Init           ; APTR  RT_INIT
  114.                          ; LABEL RT_SIZE
  115.  
  116.  
  117.      ; this is the name that the device will have
  118. subSysName:
  119. myName:        MYDEVNAME
  120.  
  121.      ; a major version number.
  122. VERSION:  EQU  1
  123.  
  124.      ; A particular revision.  This should uniquely identify the bits in the
  125.      ; device.  I use a script that advances the revision number each time
  126.      ; I recompile.  That way there is never a question of which device
  127.      ; that really is.
  128. REVISION: EQU  17
  129.  
  130.      ; this is an identifier tag to help in supporting the device
  131.      ; format is 'name version.revision (dd MON yyyy)',<cr>,<lf>,<null>
  132. idString: dc.b 'mydev 1.0 (31 Oct 1985)',13,10,0
  133.  
  134. dosName:  DOSNAME
  135.  
  136.      ; force word allignment
  137.      ds.w 0
  138.  
  139.  
  140.      ; The romtag specified that we were "RTF_AUTOINIT".  This means
  141.      ; that the RT_INIT structure member points to one of these
  142.      ; tables below.  If the AUTOINIT bit was not set then RT_INIT
  143.      ; would point to a routine to run.
  144.  
  145. Init:
  146.      DC.L MyDev_Sizeof        ; data space size
  147.      DC.L funcTable      ; pointer to function initializers
  148.      DC.L dataTable      ; pointer to data initializers
  149.      DC.L initRoutine         ; routine to run
  150.  
  151.  
  152. funcTable:
  153.  
  154.      ;------ standard system routines
  155.      dc.l Open
  156.      dc.l Close
  157.      dc.l Expunge
  158.      dc.l Null
  159.  
  160.      ;------ my device definitions
  161.      dc.l BeginIO
  162.      dc.l AbortIO
  163.  
  164.      ;------ function table end marker
  165.      dc.l -1
  166.  
  167.  
  168.      ; The data table initializes static data structures.
  169.      ; The format is specified in exec/InitStruct routine's
  170.      ; manual pages.  The INITBYTE/INITWORD/INITLONG routines
  171.      ; are in the file "exec/initializers.i".  The first argument
  172.      ; is the offset from the device base for this byte/word/long.
  173.      ; The second argument is the value to put in that cell.
  174.      ; The table is null terminated
  175. dataTable:
  176.      INITBYTE  LH_TYPE,NT_DEVICE
  177.      INITLONG  LN_NAME,myName
  178.      INITBYTE  LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
  179.      INITWORD  LIB_VERSION,VERSION
  180.      INITWORD  LIB_REVISION,REVISION
  181.      INITLONG  LIB_IDSTRING,idString
  182.      DC.L 0
  183.  
  184.  
  185.      ; This routine gets called after the device has been allocated.
  186.      ; The device pointer is in D0.  The segment list is in a0.
  187.      ; If it returns non-zero then the device will be linked into
  188.      ; the device list.
  189. initRoutine:
  190.  
  191.      ;------ get the device pointer into a convenient A register
  192.      move.l    a5,-(sp)
  193.      move.l    d0,a5
  194.  
  195.      ;------ save a pointer to exec
  196.      move.l    a6,md_SysLib(a5)
  197.  
  198.      ;------ save a pointer to our loaded code
  199.      move.l    a0,md_SegList(a5)
  200.  
  201.      ;------ open the dos library
  202.      lea  dosName(pc),a1
  203.      CLEAR     d0
  204.      CALLSYS   OpenLibrary
  205.  
  206.      move.l    d0,md_DosLib(a5)
  207.      bne.s     init_DosOK
  208.  
  209.      ;------ can't open the dos!  what gives
  210.      ALERT     AG_OpenLib!AO_DOSLib
  211.  
  212. init_DosOK:
  213.      ;------ now build the static data that we need
  214.  
  215.      ;
  216.      ; put your initialization here...
  217.      ;
  218.  
  219.      move.l    a5,d0
  220.      move.l    (sp)+,a5
  221.      rts
  222.  
  223. ;----------------------------------------------------------------------
  224. ;
  225. ; here begins the system interface commands.  When the user calls
  226. ; OpenLibrary/CloseLibrary/RemoveLibrary, this eventually gets translated
  227. ; into a call to the following routines (Open/Close/Expunge).  Exec
  228. ; has already put our device pointer in a6 for us.  Exec has turned
  229. ; off task switching while in these routines (via Forbid/Permit), so
  230. ; we should not take too long in them.
  231. ;
  232. ;----------------------------------------------------------------------
  233.  
  234.  
  235.      ; Open sets the IO_ERROR field on an error.  If it was successfull,
  236.      ; we should set up the IO_UNIT field.
  237.  
  238. Open:          ; ( device:a6, iob:a1, unitnum:d0, flags:d1 )
  239.      movem.l   d2/a2/a3/a4,-(sp)
  240.  
  241.      move.l    a1,a2          ; save the iob
  242.  
  243.      ;------ see if the unit number is in range
  244.      moveq     #MD_NUMUNITS,d2
  245.      cmp.l     d2,d0
  246.      bcc.s     Open_Error     ; unit number out of range
  247.  
  248.      ;------ see if the unit is already initialized
  249.      move.l    d0,d2          ; save unit number
  250.      lsl.l     #2,d0
  251.      lea.l     md_Units(a6,d0.l),a4
  252.      move.l    (a4),d0
  253.      bne.s     Open_UnitOK
  254.  
  255.      ;------ try and conjure up a unit
  256.      bsr  InitUnit
  257.  
  258.      ;------ see if it initialized OK
  259.      move.l    (a4),d0
  260.      beq.s     Open_Error
  261.  
  262. Open_UnitOK:
  263.      move.l    d0,a3          ; unit pointer in a3
  264.  
  265.      move.l    d0,IO_UNIT(a2)
  266.  
  267.      ;------ mark us as having another opener
  268.      addq.w    #1,LIB_OPENCNT(a6)
  269.      addq.w    #1,UNIT_OPENCNT(a3)
  270.  
  271.      ;------ prevent delayed expunges
  272.      bclr #LIBB_DELEXP,md_Flags(a6)
  273.  
  274. Open_End:
  275.  
  276.      movem.l   (sp)+,d2/a2/a3/a4
  277.      rts
  278.  
  279. Open_Error:
  280.      move.b    #IOERR_OPENFAIL,IO_ERROR(a2)
  281.      bra.s     Open_End
  282.  
  283.      ; There are two different things that might be returned from
  284.      ; the Close routine.  If the device is no longer open and
  285.      ; there is a delayed expunge then Close should return the
  286.      ; segment list (as given to Init).  Otherwise close should
  287.      ; return NULL.
  288.  
  289. Close:         ; ( device:a6, iob:a1 )
  290.      movem.l   a2/a3,-(sp)
  291.  
  292.      move.l    a1,a2
  293.  
  294.      move.l    IO_UNIT(a2),a3
  295.  
  296.      ;------ make sure the iob is not used again
  297.      moveq.l   #-1,d0
  298.      move.l    d0,IO_UNIT(a2)
  299.      move.l    d0,IO_DEVICE(a2)
  300.  
  301.      ;------ see if the unit is still in use
  302.      subq.w    #1,UNIT_OPENCNT(a3)
  303.      bne.s     Close_Device
  304.  
  305.      bsr  ExpungeUnit
  306.  
  307. Close_Device:
  308.      ;------ mark us as having one fewer openers
  309.      subq.w    #1,LIB_OPENCNT(a6)
  310.  
  311.      ;------ see if there is anyone left with us open
  312.      bne.s     Close_End
  313.  
  314.      ;------ see if we have a delayed expunge pending
  315.      btst #LIBB_DELEXP,md_Flags(a6)
  316.      beq.s     Close_End
  317.  
  318.      ;------ do the expunge
  319.      bsr  Expunge
  320.  
  321. Close_End:
  322.      movem.l   (sp)+,a2/a3
  323.      rts
  324.  
  325.  
  326.      ; There are two different things that might be returned from
  327.      ; the Expunge routine.  If the device is no longer open
  328.      ; then Expunge should return the segment list (as given to
  329.      ; Init).  Otherwise Expunge should set the delayed expunge
  330.      ; flag and return NULL.
  331.      ;
  332.      ; One other important note: because Expunge is called from
  333.      ; the memory allocator, it may NEVER Wait() or otherwise
  334.      ; take long time to complete.
  335.  
  336. Expunge:  ; ( device: a6 )
  337.  
  338.      movem.l   d2/a5/a6,-(sp)
  339.      move.l    a6,a5
  340.      move.l    md_SysLib(a5),a6
  341.      
  342.      ;------ see if anyone has us open
  343.      tst.w     LIB_OPENCNT(a5)
  344.      beq  1$
  345.  
  346.      ;------ it is still open.  set the delayed expunge flag
  347.      bset #LIBB_DELEXP,md_Flags(a5)
  348.      CLEAR     d0
  349.      bra.s     Expunge_End
  350.  
  351. 1$:
  352.      ;------ go ahead and get rid of us.  Store our seglist in d2
  353.      move.l    md_SegList(a5),d2
  354.  
  355.      ;------ unlink from device list
  356.      move.l    a5,a0
  357.      CALLSYS   Remove
  358.      
  359.      ;
  360.      ; device specific closings here...
  361.      ;
  362.  
  363.      ;------ close the dos library
  364.      move.l    md_DosLib(a5),a1
  365.      CALLSYS   CloseLibrary
  366.  
  367.      ;------ free our memory
  368.      move.l    a5,a1
  369.      move.l    LIB_NEGSIZE(a5),d0
  370.  
  371.      sub.l     d0,a1
  372.      add.l     LIB_POSSIZE(a5),d0
  373.  
  374.      CALLSYS   FreeMem
  375.  
  376.      ;------ set up our return value
  377.      move.l    d2,d0
  378.  
  379. Expunge_End:
  380.      movem.l   (sp)+,d2/a5/a6
  381.      rts
  382.  
  383.  
  384. Null:
  385.      CLEAR     d0
  386.      rts
  387.  
  388.  
  389. InitUnit: ; ( d2:unit number, a3:scratch, a6:devptr )
  390.      movem.l   d2/d3/d4,-(sp)
  391.  
  392.      ;------ allocate unit memory
  393.      move.l    #MyDevUnit_Sizeof,d0
  394.      move.l    #MEMF_PUBLIC!MEMF_CLEAR,d1
  395.      LINKSYS   AllocMem,md_SysLib(a6)
  396.  
  397.      tst.l     d0
  398.      beq  InitUnit_End
  399.  
  400.      move.l    d0,a3
  401.      move.b    d2,mdu_UnitNum(a3)  ; initialize unit number
  402.  
  403.      ;------ start up the unit process.  We do a trick here --
  404.      ;------ we set his message port to PA_IGNORE until the
  405.      ;------ new process has a change to set it up.
  406.      ;------ We cannot go to sleep here: it would be very nasty
  407.      ;------ if someone else tried to open the unit
  408.      ;------ (exec's OpenDevice has done a Forbid() for us --
  409.      ;------ we depend on this to become single threaded).
  410.      move.l    #MYPROCSTACKSIZE,d4 ; stack size
  411.      move.l    #myproc_seglist,d3  ; segment list
  412.      lsr.l     #2,d3               ; change to bcpl pointer
  413.      moveq     #MYPROCPRI,d2       ; pick out its priority
  414.      move.l    #myName,d1          ; name is the device's
  415.      LINKSYS   CreateProc,md_DosLib(a6)
  416.  
  417.      tst.l     d0
  418.      beq  InitUnit_FreeUnit
  419.  
  420.           IFGE INFO_LEVEL-1
  421.           move.l    d0,-(sp)
  422.           move.l    a3,-(sp)
  423.           PUTMSG    1,<'%s/InitUnit: unit 0x%lx process 0x%lx'>
  424.           addq.l    #8,sp
  425.           ENDC
  426.  
  427.      ;------ set up the unit structures for the new process
  428.      move.l    d0,mdu_Process(a3)
  429.      move.l    d0,a0
  430.      lea  -pr_MsgPort(a0),a0
  431.      move.l    a0,MP_SIGTASK(a3)
  432.      move.b    #PA_IGNORE,MP_FLAGS(a3)
  433.  
  434.      ;------ send a startup message to the new process
  435.      lea  mdu_Msg(a3),a1
  436.      move.l    a3,mdm_Unit(a1)
  437.      move.l    a6,mdm_Device(a1)
  438.      move.l    d0,a0               ; message port is new process port
  439.      LINKSYS   PutMsg,md_SysLib(a6)
  440.  
  441.      ;------ mark us as ready to go
  442.      move.l    d2,d0               ; unit number
  443.      lsl.l     #2,d0
  444.      move.l    a3,md_Units(a6,d0.l)     ; set unit table
  445.  
  446.  
  447. InitUnit_End:
  448.      movem.l   (sp)+,d2/d3/d4
  449.      rts
  450.  
  451.      ;------ got an error.  free the unit structure that we allocated.
  452. InitUnit_FreeUnit:
  453.      bsr  FreeUnit
  454.      bra.s     InitUnit_End
  455.  
  456. FreeUnit: ; ( a3:unitptr, a6:deviceptr )
  457.      move.l    a3,a1
  458.      move.l    #MyDevUnit_Sizeof,d0
  459.      LINKSYS   FreeMem,md_SysLib(a6)
  460.      rts
  461.  
  462.  
  463. ExpungeUnit:   ; ( a3:unitptr, a6:deviceptr )
  464.      move.l    d2,-(sp)
  465.  
  466.      ;------ get rid of the unit's task.  We know this is safe
  467.      ;------ because the unit has an open count of zero, so it
  468.      ;------ is 'guaranteed' not in use.
  469.      move.l    mdu_Process(a3),a1
  470.      lea  -(pr_MsgPort)(a1),a1
  471.      LINKSYS   RemTask,md_SysLib(a6)
  472.  
  473.      ;------ save the unit number
  474.      CLEAR     d2
  475.      move.b    mdu_UnitNum(a3),d2
  476.  
  477.      ;------ free the unit structure.
  478.      bsr  FreeUnit
  479.  
  480.      ;------ clear out the unit vector in the device
  481.      lsl.l     #2,d2
  482.      clr.l     md_Units(a6,d2.l)
  483.  
  484.      move.l    (sp)+,d2
  485.  
  486.      rts
  487.  
  488. ;----------------------------------------------------------------------
  489. ;
  490. ; here begins the device specific functions
  491. ;
  492. ;----------------------------------------------------------------------
  493.  
  494. ; cmdtable is used to look up the address of a routine that will
  495. ; implement the device command.
  496. cmdtable:
  497.      DC.L Invalid        ; $00000001
  498.      DC.L MyReset        ; $00000002
  499.      DC.L Read      ; $00000004
  500.      DC.L Write          ; $00000008
  501.      DC.L Update         ; $00000010
  502.      DC.L Clear          ; $00000020
  503.      DC.L MyStop         ; $00000040
  504.      DC.L Start          ; $00000080
  505.      DC.L Flush          ; $00000100
  506.      DC.L Foo       ; $00000200
  507.      DC.L Bar       ; $00000400
  508. cmdtable_end:
  509.  
  510. ; this define is used to tell which commands should not be queued
  511. ; command zero is bit zero.
  512. ; The immediate commands are Invalid, Reset, Stop, Start, Flush
  513. IMMEDIATES     EQU  $000001c3
  514.  
  515. ;
  516. ; BeginIO starts all incoming io.  The IO is either queued up for the
  517. ; unit task or processed immediately.
  518. ;
  519.  
  520. BeginIO:  ; ( iob: a1, device:a6 )
  521.      move.l    a3,-(sp)
  522.  
  523.      ;------ bookkeeping
  524.      move.l    IO_UNIT(a1),a3
  525.  
  526.      ;------ see if the io command is within range
  527.      move.w    IO_COMMAND(a1),d0
  528.      cmp.w     #MYDEV_END,d0
  529.      bcc.s     BeginIO_NoCmd
  530.  
  531.      DISABLE   a0
  532.  
  533.      ;------ process all immediate commands no matter what
  534.      move.w    #IMMEDIATES,d1
  535.      btst d0,d1
  536.      bne.s     BeginIO_Immediate
  537.  
  538.      ;------ see if the unit is STOPPED.  If so, queue the msg.
  539.      btst #MDUB_STOPPED,UNIT_FLAGS(a3)
  540.      bne.s     BeginIO_QueueMsg
  541.  
  542.      ;------ this is not an immediate command.  see if the device is
  543.      ;------ busy.
  544.      bset #UNITB_ACTIVE,UNIT_FLAGS(a3)
  545.      beq.s     BeginIO_Immediate
  546.  
  547.      ;------ we need to queue the device.  mark us as needing
  548.      ;------ task attention.  Clear the quick flag
  549. BeginIO_QueueMsg:
  550.      BSET #UNITB_INTASK,UNIT_FLAGS(a3)
  551.      bclr #IOB_QUICK,IO_FLAGS(a1)
  552.  
  553.      ENABLE    a0
  554.  
  555.      move.l    a3,a0
  556.      LINKSYS   PutMsg,md_SysLib(a6)
  557.      bra.s     BeginIO_End
  558.  
  559. BeginIO_Immediate:
  560.      ENABLE    a0
  561.  
  562.      bsr  PerformIO
  563.  
  564. BeginIO_End:
  565.      move.l    (sp)+,a3
  566.      rts
  567.  
  568. BeginIO_NoCmd:
  569.      move.b    #IOERR_NOCMD,IO_ERROR(a1)
  570.      bra.s     BeginIO_End
  571.  
  572.  
  573. ;
  574. ; PerformIO actually dispatches an io request.  It expects a3 to already
  575. ; have the unit pointer in it.  a6 has the device pointer (as always).
  576. ; a1 has the io request.  Bounds checking has already been done on
  577. ; the io request.
  578. ;
  579.  
  580. PerformIO:     ; ( iob:a1, unitptr:a3, devptr:a6 )
  581.      move.l    a2,-(sp)
  582.      move.l    a1,a2
  583.  
  584.      move.w    IO_COMMAND(a2),d0
  585.      lea  cmdtable(pc),a0
  586.      move.l    0(a0,d0.w),a0
  587.  
  588.      jsr  (a0)
  589.  
  590.      move.l    (sp)+,a2
  591.      rts
  592.  
  593. ;
  594. ; TermIO sends the IO request back to the user.  It knows not to mark
  595. ; the device as inactive if this was an immediate request or if the
  596. ; request was started from the server task.
  597. ;
  598.  
  599. TermIO:        ; ( iob:a1, unitptr:a3, devptr:a6 )
  600.      move.w    IO_COMMAND(a1),d0
  601.      move.w    #IMMEDIATES,d1
  602.      btst d0,d1
  603.      bne.s     TermIO_Immediate
  604.  
  605.      ;------ we may need to turn the active bit off.
  606.      btst #UNITB_INTASK,UNIT_FLAGS(a3)
  607.      bne.s     TermIO_Immediate
  608.  
  609.      ;------ the task does not have more work to do
  610.      bclr #UNITB_ACTIVE,UNIT_FLAGS(a3)
  611.  
  612. TermIO_Immediate:
  613.      ;------ if the quick bit is still set then we don't need to reply
  614.      ;------ msg -- just return to the user.
  615.      btst #IOB_QUICK,IO_FLAGS(a1)
  616.      bne.s     TermIO_End
  617.  
  618.      LINKSYS   ReplyMsg,md_SysLib(a6)
  619.  
  620. TermIO_End:
  621.      rts
  622.      
  623.  
  624. AbortIO:  ; ( iob: a1, device:a6 )
  625.  
  626. ;----------------------------------------------------------------------
  627. ;
  628. ; here begins the functions that implement the device commands
  629. ; all functions are called with:
  630. ;    a1 -- a pointer to the io request block
  631. ;    a2 -- another pointer to the iob
  632. ;    a3 -- a pointer to the unit
  633. ;    a6 -- a pointer to the device
  634. ;
  635. ; Commands that conflict with 68000 instructions have a "My" prepended
  636. ; to them.
  637. ;----------------------------------------------------------------------
  638.  
  639. Invalid:
  640.      move.b    #IOERR_NOCMD,IO_ERROR(a1)
  641.      bsr  TermIO
  642.      rts
  643.  
  644. MyReset:
  645.  
  646.      ; !!! fill me in !!!
  647.      ; !!! fill me in !!!
  648.      ; !!! fill me in !!!
  649.      ; !!! fill me in !!!
  650.  
  651.  
  652. ;
  653. ; the Read command acts as an infinite source of nulls.  It clears
  654. ; the user's buffer and marks that many bytes as having been read.
  655. ;
  656.  
  657. Read:
  658.      move.l    IO_DATA(a1),a0
  659.      move.l    IO_LENGTH(a1),d0
  660.      move.l    d0,IO_ACTUAL(a1)
  661.  
  662.      ;------ deal with a zero length read
  663.      beq.s     Read_End
  664.  
  665.      ;------ now copy the data
  666.      CLEAR     d1
  667.  
  668. Read_Loop:
  669.      move.b    d1,(a0)+
  670.      subq.l    #1,d0
  671.      bne.s     Read_Loop
  672.  
  673. Read_End:
  674.      bsr  TermIO
  675.      rts
  676.  
  677.  
  678. ;
  679. ; the Write command acts as bit bucket.  It clears acknowledges all
  680. ; the bytes the user has tried to write to it.
  681. ;
  682.  
  683. Write:
  684.      move.l    IO_LENGTH(a1),IO_ACTUAL(a1)
  685.  
  686.      bsr  TermIO
  687.      rts
  688.  
  689. ;
  690. ; Update and Clear are internal buffering commands.  Update forces all
  691. ; io out to its final resting spot, and does not return until this is
  692. ; done.  Clear invalidates all internal buffers.  Since this device
  693. ; has no internal buffers, these commands do not apply.
  694. ;
  695.  
  696. Update:
  697. Clear:
  698.      bra  Invalid
  699.  
  700. ;
  701. ; the Stop command stop all future io requests from being
  702. ; processed until a Start command is received.  The Stop
  703. ; command is NOT stackable: e.g. no matter how many stops
  704. ; have been issued, it only takes one Start to restart
  705. ; processing.
  706. ;
  707.  
  708. MyStop:
  709.      bset #MDUB_STOPPED,UNIT_FLAGS(a3)
  710.  
  711.      bsr  TermIO
  712.      rts
  713.      
  714. Start:
  715.      bsr  InternalStart
  716.  
  717.      move.l    a2,a1
  718.      bsr  TermIO
  719.  
  720.      rts
  721.  
  722. InternalStart:
  723.      ;------ turn processing back on
  724.      bclr #MDUB_STOPPED,UNIT_FLAGS(a3)
  725.  
  726.      ;------ kick the task to start it moving
  727.      move.l    a3,a1
  728.      CLEAR     d0
  729.      move.l    MP_SIGBIT(a3),d1
  730.      bset d1,d0
  731.      LINKSYS   Signal,md_SysLib(a3)
  732.  
  733.      rts
  734.  
  735. ;
  736. ; Flush pulls all io requests off the queue and sends them back.
  737. ; We must be careful not to destroy work in progress, and also
  738. ; that we do not let some io requests slip by.
  739. ;
  740. ; Some funny magic goes on with the STOPPED bit in here.  Stop is
  741. ; defined as not being reentrant.  We therefore save the old state
  742. ; of the bit and then restore it later.  This keeps us from
  743. ; needing to DISABLE in flush.  It also fails miserably if someone
  744. ; does a start in the middle of a flush.
  745. ;
  746.  
  747. Flush:
  748.      movem.l   d2/a6,-(sp)
  749.  
  750.      move.l    md_SysLib(a6),a6
  751.  
  752.      bset #MDUB_STOPPED,UNIT_FLAGS(a3)
  753.      sne  d2
  754.  
  755. Flush_Loop:
  756.      move.l    a3,a0
  757.      CALLSYS   GetMsg
  758.  
  759.      tst.l     d0
  760.      beq.s     Flush_End
  761.  
  762.      move.l    d0,a1
  763.      move.b    #IOERR_ABORTED,IO_ERROR(a1)
  764.      CALLSYS   ReplyMsg
  765.  
  766.      bra.s     Flush_Loop
  767.  
  768. Flush_End:
  769.  
  770.      move.l    d2,d0
  771.      movem.l   (sp)+,d2/a6
  772.  
  773.      tst.b     d0
  774.      beq.s     1$
  775.  
  776.      bsr  InternalStart
  777. 1$:
  778.  
  779.      move.l    a2,a1
  780.      bsr  TermIO
  781.  
  782.      rts
  783.  
  784. ;
  785. ; Foo and Bar are two device specific commands that are provided just
  786. ; to show you how to add your own commands.  The currently return that
  787. ; no work was done.
  788. ;
  789.  
  790. Foo:
  791. Bar:
  792.      CLEAR     d0
  793.      move.l    d0,IO_ACTUAL(a1)
  794.  
  795.      bsr  TermIO
  796.      rts
  797.  
  798. ;----------------------------------------------------------------------
  799. ;
  800. ; here begins the process related routines
  801. ;
  802. ; A Process is provided so that queued requests may be processed at
  803. ; a later time.
  804. ;
  805. ;
  806. ; Register Usage
  807. ; ==============
  808. ; a3 -- unit pointer
  809. ; a6 -- syslib pointer
  810. ; a5 -- device pointer
  811. ; a4 -- task (NOT process) pointer
  812. ; d7 -- wait mask
  813. ;
  814. ;----------------------------------------------------------------------
  815.  
  816. ; some dos magic.  A process is started at the first executable address
  817. ; after a segment list.  We hand craft a segment list here.  See the
  818. ; the DOS technical reference if you really need to know more about this.
  819.  
  820.      cnop 0,4            ; long word allign
  821.      DC.L 16             ; segment length -- any number will do
  822. myproc_seglist:
  823.      DC.L 0              ; pointer to next segment
  824.  
  825. ; the next instruction after the segment list is the first executable address
  826.  
  827. Proc_Begin:
  828.  
  829.      move.l    _AbsExecBase,a6
  830.  
  831.           PUTMSG    1,<'%s/Proc: called'>
  832.           XLIB Debug
  833.           CALLSYS   Debug
  834.  
  835.      ;------ wait for our first packet
  836.      SUB.L     a1,a1               ; <my task> = FindTask(0)
  837.      CALLSYS   FindTask
  838.      move.l    d0,a0
  839.      move.l    d0,a4               ; save task in a4
  840.      lea  pr_MsgPort(a0),a0   ; get msg port for my processes
  841.      CALLSYS   WaitPort
  842.  
  843.      ;------ take msg off the port
  844.      move.l    d0,a1
  845.      move.l    d0,a2               ; save the message
  846.      CALLSYS   Remove
  847.  
  848.      ;------ get our parameters out of it
  849.      move.l    mdm_Device(a2),a5        ; a5 is now our device
  850.      move.l    mdm_Unit(a2),a3
  851.  
  852.           IFGE INFO_LEVEL-1
  853.           pea  0
  854.           move.b    mdu_UnitNum(a3),3(sp)
  855.           move.l    a3,-(sp)
  856.           move.l    a5,-(sp)
  857.           PUTMSG    1,<'%s/Proc: dev 0x%lx unit 0x%lx/%ld'>
  858.           lea  12(sp),sp
  859.           ENDC
  860.  
  861.      ;------ Allocate the right signal
  862.      moveq     #-1,d0              ; -1 is any signal at all
  863.      CALLSYS   AllocSignal
  864.  
  865.      move.b    d0,MP_SIGBIT(a3)
  866.      move.b    #PA_SIGNAL,MP_FLAGS(a3)
  867.  
  868.      ;------ change the bit number into a mask, and save in d7
  869.      CLEAR     d7
  870.      bset d0,d7
  871.  
  872.  
  873.      ;------
  874.      ;------ OK, kids, we are done with initialization.  We now
  875.      ;------ can start the main loop of the driver.  It goes
  876.      ;------ like this.  Because we had the port marked PA_IGNORE
  877.      ;------ for a while (in InitUnit) we jump to the getmsg
  878.      ;------ code on entry.
  879.      ;------
  880.      ;------        wait for a message
  881.      ;------        lock the device
  882.      ;------        get a message.  if no message unlock device and loop
  883.      ;------        dispatch the message
  884.      ;------        loop back to get a message
  885.      ;------
  886.  
  887.      bra.s     Proc_CheckStatus
  888.  
  889.      ;------ main loop: wait for a new message
  890. Proc_MainLoop:
  891.      move.l    d7,d0
  892.      CALLSYS   Wait
  893.  
  894. Proc_CheckStatus:
  895.      ;------ see if we are stopped
  896.      btst #MDUB_STOPPED,UNIT_FLAGS(a3)
  897.      bne.s     Proc_MainLoop       ; device is stopped
  898.  
  899.      ;------ lock the device
  900.      bset #UNITB_ACTIVE,UNIT_FLAGS(a3)
  901.      bne.s     Proc_MainLoop       ; device in use
  902.  
  903.      ;------ get the next request
  904. Proc_NextMessage:
  905.      move.l    a3,a0
  906.      CALLSYS   GetMsg
  907.      tst.l     d0
  908.      beq.s     Proc_Unlock         ; no message?
  909.  
  910.      ;------ do this request
  911.      move.l    d0,a1
  912.      exg  a5,a6               ; put device ptr in right place
  913.      bsr  PerformIO
  914.      exg  a5,a6               ; get syslib back in a6
  915.  
  916.      bra.s     Proc_NextMessage
  917.  
  918.      ;------ no more messages.  back ourselves out.
  919. Proc_Unlock:
  920.      and.b     #$ff&(UNITB_ACTIVE!UNITB_INTASK),UNIT_FLAGS(a3)
  921.      bra  Proc_MainLoop
  922.  
  923.  
  924. Proc_Fail:
  925.      ;------ we come here on initialization failures
  926.      bsr  FreeUnit
  927.      rts
  928.  
  929.  
  930. ;----------------------------------------------------------------------
  931. ; EndCode is a marker that show the end of your code.
  932. ; Make sure it does not span sections nor is before the
  933. ; rom tag in memory!  It is ok to put it right after
  934. ; the rom tag -- that way you are always safe.  I put
  935. ; it here because it happens to be the "right" thing
  936. ; to do, and I know that it is safe in this case.
  937. ;----------------------------------------------------------------------
  938. EndCode:
  939.  
  940.      END
  941.  
  942.